package com.sunxd.integration.platform.controller;

import com.sunxd.integration.platform.classloader.MyClassLoader;
import com.sunxd.integration.platform.post.MyBeanDefinitionRegistryPostProcessor;
import com.sunxd.integration.platform.util.SpringUtil;
import com.sunxd.integration.platform.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

import static com.sunxd.integration.platform.constants.ClassLoaderConstant.DUBBO_SRC;
import static com.sunxd.integration.platform.constants.ClassLoaderConstant.HTTP_SRC;

/**
 * @author sun.xd
 * @description: description
 * @date 2022/9/7 15:40
 */
@Slf4j
@RestController
@RequestMapping("/mapping")
public class RequestMappingController {

    @Resource
    private RequestMappingHandlerMapping requestMappingHandlerMapping;
    @Resource
    private ApplicationContext applicationContext;

    @Resource
    private MyBeanDefinitionRegistryPostProcessor myBeanDefinitionRegistryPostProcessor;


    /**
     * @return
     */
    @RequestMapping("api/**")
    public Object api() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest httpServletRequest = servletRequestAttributes.getRequest();
        HttpServletResponse httpServletResponse = servletRequestAttributes.getResponse();
        return httpServletRequest.getRequestURI();
    }

    @GetMapping("allMapping")
    public void allMapping() {
        Map<RequestMappingInfo, HandlerMethod> mappings = requestMappingHandlerMapping.getHandlerMethods();
        log.info("mappings size:{}", mappings.size());
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : mappings.entrySet()) {
            log.info("key:{},value:{}", entry.getKey(), entry.getValue());
        }
    }

    /**
     * 动态注册路径映射
     *
     * @param data
     * @return
     */
    @PostMapping("registerMapping")
    public RequestMappingInfo registerMapping(@RequestBody Map data) throws IOException, ClassNotFoundException {
        String beanSimpleName = data.get("beanSimpleName").toString();
        String urlPath = data.get("urlPath").toString();
        String str = HTTP_SRC.replaceAll("#beanSimpleName#", beanSimpleName);
        str = str.replaceAll("#urlPath#", urlPath);
        MyClassLoader myClassLoader = new MyClassLoader(beanSimpleName, str);
        Class<?> clazz = myClassLoader.dynamicLoadClass();
        //将applicationContext转换为ConfigurableApplicationContext
        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) SpringUtil.getApplicationContext();
        // 获取bean工厂并转换为DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
        myBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(defaultListableBeanFactory);
        RequestMappingInfo mappingInfo = RequestMappingInfo.paths(urlPath).build();
        Object bean = applicationContext.getBean(StringUtils.toLowerCaseFirstOne(beanSimpleName));
        try {
            requestMappingHandlerMapping.registerMapping(mappingInfo, bean, bean.getClass().getDeclaredMethod("execute", Map.class));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return mappingInfo;
    }

    /**
     * 动态注册路径映射
     *
     * @param data
     * @return
     */
    @PostMapping("registerDubbo")
    public RequestMappingInfo registerDubbo(@RequestBody Map data) throws IOException, ClassNotFoundException {
        String beanSimpleName = data.get("beanSimpleName").toString();
        String urlPath = data.get("urlPath").toString();
        String str = DUBBO_SRC.replaceAll("#beanSimpleName#", beanSimpleName);
        str = str.replaceAll("#urlPath#", urlPath);
        MyClassLoader myClassLoader = new MyClassLoader(beanSimpleName, str);
        Class<?> clazz = myClassLoader.dynamicLoadClass();
        //将applicationContext转换为ConfigurableApplicationContext
        ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) SpringUtil.getApplicationContext();
        // 获取bean工厂并转换为DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
        myBeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry(defaultListableBeanFactory);
        RequestMappingInfo mappingInfo = RequestMappingInfo.paths(urlPath).build();
        Object bean = applicationContext.getBean(StringUtils.toLowerCaseFirstOne(beanSimpleName));
        try {
            requestMappingHandlerMapping.registerMapping(mappingInfo, bean, bean.getClass().getDeclaredMethod("execute", Map.class));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return mappingInfo;
    }

    /**
     * 动态删除路径映射
     *
     * @param data
     * @return
     */
    @PostMapping("unregisterMapping")
    public RequestMappingInfo unregisterMapping(@RequestBody Map data) {
        RequestMappingInfo mappingInfo = RequestMappingInfo.paths(data.get("path").toString()).build();
        requestMappingHandlerMapping.unregisterMapping(mappingInfo);
        return mappingInfo;
    }


}
